iT邦幫忙

2024 iThome 鐵人賽

DAY 19
0
Modern Web

前進React 生態系 : 技術應用與概念解析系列 第 19

Day 19 - Server Functions、action prop 與新的 Hooks

  • 分享至 

  • xImage
  •  

Server Functions 使用

Server Function 可以在 Client Component 和 Server Component 中使用。

如果 Server Function 在 Client Component 使用要非常小心,有可能將機密資訊傳到 Client 端,建議先不要在 production 環境使用。

除此之外,還有另一種使用方式是和 React 19 新的表單功能使用。當 Server Function 傳給 action props 或在 action 使用,又被稱做 Server Action。

action

在 form 中使用 action prop

在 React 中的 <form> 元素的 action prop 可以接收 URL 或函數。傳入 URL 時,表單將像標準 HTML 一樣提交。但傳入函數時,該函數會負責處理表單的提交行為。這就可以取代傳統的事件處理,如 onSubmit

使用範例:

export default function Search() {
  function search(formData: FormData) {
    const query = formData.get("query");
    //... 其他邏輯
  }

  return (
    <form action={search}>
      <input name="query" />
      <button type="submit">Search</button>
    </form>
  );
}

action 的函數中,表單提交的內容會透過 FormData 格式傳遞。

formAction

除了 元素上的 action prop 外,React 也允許在 、 和 元素上使用 formAction prop。formAction 會覆蓋掉父層 的 action 設定,同樣可以傳入 URL 或函數來處理提交邏輯。

另外要注意的是,無論在 中指定了什麼 method,當傳遞函數給 actionformAction 時,表單的 HTTP method 始終為 POST。

為什麼使用 action 或 formAction?

有一個重要的好處:即使 JavaScript 被禁用,表單依然能正常提交。這意味著你可以使用 Server Components 來處理表單提交,而不依賴 JavaScript 事件,如 onSubmit

為了更好的管理 action 相關的狀態, React 提供了許多相關的 Hook。

useActionState

useActionState 是 React 19 的 Hook,用來管理表單提交的狀態。根據表單操作的結果來更新狀態,並且能夠提供初始狀態,在表單操作後返回新的狀態。

表單狀態是上次提交表單時操作返回的值。如果尚未提交表單,則會是傳遞的初始狀態。

基本範例:

const [state, formAction] = useActionState(fn, initialState, permalink?);
  • fn : 提交表單或按下按鈕時要使用的函數。它會接收表單的前一個狀態(初始為 initialState,後續會是先前的返回值)作為第一個參數,接著會收到表單提交時會傳遞的其他參數 (formData)。
  • initialState : 狀態初始值,可以是任何可序列化的值。
  • permalink (可選) : 允許在 JavaScript 未載入前進行漸進式增強(Progressive Enhancement)。如果表單是在 JavaScript bundle 載入之前提交的,React 會 redirect 到提供的 URL。
  • state: 表單的當前狀態,最剛開始會是初始值,在提交表單後會是操作後返回的狀態。
  • formAction: 用來傳給 <form> 元素的 actionformAction props。

補充: 什麼是漸進式增強(Progressive Enhancement) ?

漸進式增強(Progressive Enhancement)是一種網頁開發的設計策略,目的是確保網頁和應用程式能夠在各種環境中正常運作,無論是基本的舊設備或現代的高端設備,使用者都能獲得良好的體驗。


說明範例:

import { useActionState } from "react";

async function increment(previousState, formData) {
  return previousState + 1;
}

function StatefulForm({}) {
  const [state, formAction] = useActionState(increment, 0);
  return (
    <form>
      {state}
      <button formAction={formAction}>Increment</button>
    </form>
  );
}

useFormStatus

useFormStatus 是 React 19 的 Hook,用來取得父層 <form> 的狀態,而不需要使用 props 傳遞。

基本範例:

const { pending, data, method, action } = useFormStatus();
  • pending : 表單是否正在提交中,會是一個 boolean 值。
  • data : 會是一個 FormData 的物件,包含父級 <form> 正在提交的數據。如果沒有活動提交或沒有父層 <form>,則會是 null
  • method : 會是一個 'get' 或 'post' 的字串值,表示表單使用的 HTTP 方法。默認情況使用 GET。
  • action : 父層 <form> 上的 action prop 的函數,如果沒有action的 props 或傳入的是 URI,或是沒有父層 <form>,則都會是 null

需要特別注意,useFormStatus 需要在 <form> 內部的子元件使用,useFormStatus 只會返回返回該父層 <form> 的狀態資訊,不會返回在同一元件或子元件中的任何 <form> 的狀態資訊。使用範例會像下面這樣。

function Form() {
  //這是 useFormStatus 追蹤的 form
  return (
    <form action={submit}>
      {/* ...其他表單元素 */}
      <Submit />
    </form>
  );
}

function Submit() {
  // 這樣使用才是有效的
  const { pending } = useFormStatus();
  return <button disabled={pending}>submit</button>;
}

參考資料:
https://react.dev/blog/2024/04/25/react-19
https://19.react.dev/reference/rsc/server-functions
https://19.react.dev/reference/react/useActionState
https://developer.mozilla.org/zh-CN/docs/Web/HTML/Element/form
https://developer.mozilla.org/zh-CN/docs/Glossary/Progressive_Enhancement


上一篇
Day 18 - 掌握 Server Functions、Client 和 Server Components 的互動技巧
下一篇
Day 20 - 使用 React 19 的 useOptimistic 和 Transitions 打造順暢體驗
系列文
前進React 生態系 : 技術應用與概念解析30
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言